﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using EquationSolver;
using AdaptiveAgents.Tools;
using EquationSolver;


namespace AdaptiveAgents
{
    class ProjectCheckingTool
    {
        private GameRecord m_grDataBase;        
        private DataTable m_dtOutputTable;
        private List<double[]> m_lListToPrint;
        
        
        public ProjectCheckingTool()
        {
            m_grDataBase = new GameRecord();
            m_dtOutputTable = new DataTable();
            m_lListToPrint = new List<double[]>();
        }
        
        private AgentInfo[] calculateProbabilities(AgentInfo agent0, AgentInfo agent1, AgentInfo agent2)
        {
            AgentInfo[] returnVec = new AgentInfo[3];          
            EquationSolver.EquationSolver solver = new EquationSolver.EquationSolver();

            int agentLevel0, agentLevel1, agentLevel2;
            double[] EquationVector0 = new double [4];
            double[] EquationVector1 = new double [4];
            double[] EquationVector2 = new double [4];
            double[] EquationVector3 = new double[4];

            double[] answerVec0 = null;
            double[] answerVec1 = null;
            double[] answerVec2 = null;
            double[] answerVec3 = null;

            double[] cloneVec0 = null;
            double[] cloneVec1 = null;
            double[] cloneVec2 = null;
            double[] cloneVec3 = null;


            if ((agent0.getCompetence() != agent1.getCompetence()) && (agent0.getCompetence() != agent2.getCompetence()) && (agent2.getCompetence() != agent1.getCompetence()))
            {
                
                agentLevel0 = AgentComperator.getAgentLevel(agent0, agent1, agent2);
                agentLevel1 = AgentComperator.getAgentLevel(agent1, agent0, agent2);
                agentLevel2 = AgentComperator.getAgentLevel(agent2, agent1, agent0);

                EquationVector0[0] = (-1);
                EquationVector0[1] = (-1);
                EquationVector0[2] = (-1);
                EquationVector0[3] = (-1);

                EquationVector1[0] = agent0.getEpsilonTo0(agentLevel0,agentLevel0) - 1;
                EquationVector1[1] = agent1.getEpsilonTo0(agentLevel1,agentLevel0);
                EquationVector1[2] = agent2.getEpsilonTo0(agentLevel2,agentLevel0);
                EquationVector1[3] = 0;

                EquationVector2[0] = agent0.getEpsilonTo1(agentLevel0,agentLevel1);
                EquationVector2[1] = agent1.getEpsilonTo1(agentLevel1,agentLevel1) - 1;
                EquationVector2[2] = agent2.getEpsilonTo1(agentLevel2,agentLevel1);
                EquationVector2[3] = 0;

                EquationVector3[0] = agent0.getEpsilonTo2(agentLevel0,agentLevel2);
                EquationVector3[1] = agent1.getEpsilonTo2(agentLevel1,agentLevel2);
                EquationVector3[2] = agent2.getEpsilonTo2(agentLevel2,agentLevel2) - 1;
                EquationVector3[3] = 0;

                cloneVec0 = (double[])EquationVector0.Clone();
                cloneVec1 = (double[])EquationVector1.Clone();
                cloneVec2 = (double[])EquationVector2.Clone();
                cloneVec3 = (double[])EquationVector3.Clone();
            }
            
            solver.addEquation(EquationVector0);
            solver.addEquation(EquationVector1);
            solver.addEquation(EquationVector2);
            answerVec0 = solver.solve();

            solver.clear();
            EquationVector0 = (double[])cloneVec0.Clone();
            EquationVector1 = (double[])cloneVec1.Clone();
            EquationVector3 = (double[])cloneVec3.Clone();
            solver.addEquation(EquationVector0);
            solver.addEquation(EquationVector1);
            solver.addEquation(EquationVector3);
            answerVec1 = solver.solve();

            solver.clear();
            EquationVector0 = (double[])cloneVec0.Clone();
            EquationVector2 = (double[])cloneVec2.Clone();
            EquationVector3 = (double[])cloneVec3.Clone();
            solver.addEquation(EquationVector0);
            solver.addEquation(EquationVector2);
            solver.addEquation(EquationVector3);
            answerVec2 = solver.solve();


            /*solver.clear();
            EquationVector1 = (double[])cloneVec1.Clone();
            EquationVector2 = (double[])cloneVec2.Clone();
            EquationVector3 = (double[])cloneVec3.Clone();
            solver.addEquation(EquationVector1);
            solver.addEquation(EquationVector2);
            solver.addEquation(EquationVector3);
            answerVec3 = solver.solve();
            */

            if (answerVec0[0] + answerVec0[1] + answerVec0[2] == 1)
            {
                agent0.setProbabilities(answerVec0[0]);
                agent1.setProbabilities(answerVec0[1]);
                agent2.setProbabilities(answerVec0[2]);
            }
            else if (answerVec1[0] + answerVec1[1] + answerVec1[2] == 1)
            {
                agent0.setProbabilities(answerVec1[0]);
                agent1.setProbabilities(answerVec1[1]);
                agent2.setProbabilities(answerVec1[2]);
            }
            else
            {                
                agent0.setProbabilities(answerVec2[0]);
                agent1.setProbabilities(answerVec2[1]);
                agent2.setProbabilities(answerVec2[2]);
            }

            returnVec[0] = agent0;
            returnVec[1] = agent1;
            returnVec[2] = agent2;

            return returnVec;
        }

        private AgentInfo[] sortAgentArray(AgentInfo[] array)
        {
            AgentInfo[] sortedArray = new AgentInfo[3];
            int temp = array[0].getIndex();
            sortedArray[temp] = array[0];
            temp = array[1].getIndex();
            sortedArray[temp] = array[1];
            temp = array[2].getIndex();
            sortedArray[temp] = array[2];
            return sortedArray;
        }

        private void WriteToCSV(String fileName, DataTable dt)
        {
            //set an output writer
            System.IO.TextWriter writer = new System.IO.StreamWriter(fileName);

            //print columns name
            for (int i = 0; i < dt.Columns.Count; ++i)
                writer.Write(dt.Columns[i].ToString() + ",");

            writer.WriteLine();

            //for each row...
            for (int i = 0; i < dt.Rows.Count; ++i)
            {
                DataRow row = dt.Rows[i];
                //for each cell in the row...
                for (int j = 0; j < dt.Columns.Count; ++j)
                    writer.Write(row[j].ToString() + ",");
                writer.WriteLine();
            }

            writer.Close();
        }

        public void addRecord(Record rec)
        {
            m_grDataBase.addRecord(rec); 
        }

        public double[] solveRecord(Record rec)
        {
            AgentInfo agent0 = new AgentInfo(0, rec.getEpsilon(0), rec.getCompetence(0), new ProbabilityCreatorSecondVersion(rec.getEpsilon(0)));
            AgentInfo agent1 = new AgentInfo(1, rec.getEpsilon(1), rec.getCompetence(1), new ProbabilityCreatorSecondVersion(rec.getEpsilon(1)));
            AgentInfo agent2 = new AgentInfo(2, rec.getEpsilon(2), rec.getCompetence(2), new ProbabilityCreatorSecondVersion(rec.getEpsilon(2)));
            AgentInfo[] answer = calculateProbabilities(agent0, agent1, agent2);
            double[] returnVec = { answer[0].getProbabilitiea(), answer[1].getProbabilitiea(), answer[2].getProbabilitiea() };

            return returnVec;
        }

        public void solveDataBase()
        {
            Record tempRec;
            

            for (int i = 0; i < m_grDataBase.length(); ++i)
            {
                tempRec = m_grDataBase.getRecord(i);
                AgentInfo agent0 = new AgentInfo(0, tempRec.getEpsilon(0), tempRec.getCompetence(0), new ProbabilityCreatorSecondVersion(tempRec.getEpsilon(0)));
                AgentInfo agent1 = new AgentInfo(1, tempRec.getEpsilon(1), tempRec.getCompetence(1), new ProbabilityCreatorSecondVersion(tempRec.getEpsilon(1)));
                AgentInfo agent2 = new AgentInfo(2, tempRec.getEpsilon(2), tempRec.getCompetence(2), new ProbabilityCreatorSecondVersion(tempRec.getEpsilon(2)));

                AgentInfo[] answer = calculateProbabilities(agent0, agent1, agent2);
                double[] tempArray = new double[16];
                tempArray[0] = answer[0].getProbabilitiea();
                tempArray[1] = answer[1].getProbabilitiea();
                tempArray[2] = answer[2].getProbabilitiea();



                FullRecord fullRec = new FullRecord(tempRec, tempArray, i);
                tempArray = fullRec.getFullRecord();
                m_lListToPrint.Add(tempArray);
            }
        }

        public void printResultToCSVFile()
        {
            DataTable printOut = new DataTable("Result_Of_Project_Checking_Tool");
            DataRow row;
            double[] tempArray;

            DataColumn cln = new DataColumn("Game_Number", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Competence2", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Competence1", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Competence0", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Epsilon2", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Epsilon1", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Epsilon0", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Player2NumOfTurnsPlayed", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Player1NumOfTurnsPlayed", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("Player0NumOfTurnsPlayed", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("TheRelativeOfAgent2", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("TheRelativeOfAgent1", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("TheRelativeOfAgent0", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("ProbabilitiyOfAgent2", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("ProbabilitiyOfAgent1", typeof(double));
            printOut.Columns.Add(cln);
            cln = new DataColumn("ProbabilitiyOfAgent0", typeof(double));
            printOut.Columns.Add(cln);

            for (int i = 0; i < m_lListToPrint.Count; ++i)
            {
                row = printOut.NewRow();
                tempArray = m_lListToPrint[i];

                row["ProbabilitiyOfAgent0"] = tempArray[0];
                row["ProbabilitiyOfAgent1"] = tempArray[1];
                row["ProbabilitiyOfAgent2"] = tempArray[2];

                row["TheRelativeOfAgent0"] = tempArray[3];
                row["TheRelativeOfAgent1"] = tempArray[4];
                row["TheRelativeOfAgent2"] = tempArray[5];

                row["Player0NumOfTurnsPlayed"] = tempArray[6];
                row["Player1NumOfTurnsPlayed"] = tempArray[7];
                row["Player2NumOfTurnsPlayed"] = tempArray[8];

                row["Epsilon0"] = tempArray[9];
                row["Epsilon1"] = tempArray[10];
                row["Epsilon2"] = tempArray[11];

                row["Competence0"] = tempArray[12];
                row["Competence1"] = tempArray[13];
                row["Competence2"] = tempArray[14];

                row["Game_Number"] = tempArray[15];

                printOut.Rows.Add(row);
            }
            String stamp = DateTime.Now.ToString("yyyy.MM.dd-HH.mm.ss");
            WriteToCSV("Result_Of_Project_Checking_Tool_" + stamp + ".csv", printOut);
        }

        public void clear()
        {
            m_dtOutputTable.Clear();
            m_lListToPrint.Clear();
            m_grDataBase.clear();
        }

    }
}
